home *** CD-ROM | disk | FTP | other *** search
- /* dial custom gadget implementation */
-
- /* MAKE SURE YOU COMPILE THIS FILE WITH STACK CHECKING TURNED OFF. */
-
- /*
- Copyright (c) 1989 Commodore-Amiga, Inc.
-
- Executables based on this information may be used in software
- for Commodore Amiga computers. All other rights reserved.
- This information is provided "as is"; no warranties are made.
- All use is at your own risk, and no liability or responsibility
- is assumed.
- */
-
- /*
- * Limitations:
- * no RELWIDTH/RELHEIGHT (uses Width/Height)
- * no ActivateGadget() or manual toggling of SELECTED
- * Image rendering only, no SelectImage.
- */
-
- #include "math.h"
- #include "sysall.h"
-
- struct Gadget *CreateGadget();
-
- #define D( x ) ; /* debugging: on 'x', off ';' */
-
- #define DGAVECS (6) /* area info vectors for needle */
-
- /*** black box dial gadget data ***/
- struct DialInfo {
- WORD coordX; /* ray vector of needle */
- WORD coordY;
- WORD baseX; /* vector for base of needle */
- WORD baseY;
- struct AreaInfo ainfo;
- struct TmpRas tmpras;
- UBYTE abuffer[ DGAVECS * 5 ];
- };
- #define DI( g ) ( (struct DialInfo *) (g)->SpecialInfo )
-
- #define BASEFACTOR (10) /* relative width of needle */
- #define NEEDLEPEN (1) /* pen color of needle */
- #define CENTER(dim) (((dim) - 1)/2)
-
- /*** hook implementations ***/
- /* forward in this file */
- ULONG dial_Dispatch(); /* vectors off to the others */
- ULONG dial_render();
- ULONG dial_handleinput();
-
- /* see StrDemo/strhooks.c for more info on this
- * particular implementation of a Hook callback
- * asm-to-C interface routine.
- */
- ULONG __saveds __asm
- hookEntry( register __a0 struct Hook *hookptr,
- register __a2 void *object,
- register __a1 void *message )
- {
- D( kprintf("hookEntry\n"));
- return ( (*hookptr->h_SubEntry)( hookptr, object, message ) );
- }
-
- /* interface to get my dispatcher called by Intuition.
- * this hook can be shared between several dial gadgets
- */
- struct Hook dialhook = { {0,0}, hookEntry, dial_Dispatch, 0 };
-
- struct Gadget *
- CreateDialGadget( id, im )
- struct Image *im;
- {
- struct Gadget *g;
- struct DialInfo *di;
- UBYTE *tmpraster;
- int rassize;
-
- D( printf( "CDG: id: %lx, im %lx\n", id, im ) );
-
- if ( g = CreateGadget( im->Width, im->Height, id, NULL,
- sizeof ( struct DialInfo ) ) )
- {
- di = DI( g );
-
- g->GadgetType = CUSTOMGADGET;
- g->Flags |= GADGIMAGE;
- g->MutualExclude = (ULONG) &dialhook;
- g->GadgetRender = (APTR) im;
-
- SetDialCoords( g, 0, 1 ); /* initially "north" */
-
- /* need to set up a temp raster for a dial gadget
- * as well as AreaInfo.
- * could probably arrange to share tmp rasters between
- * dial gadgets no problem, via a SetDialGadgetTmpRaster()
- * function call
- */
- InitArea( &di->ainfo, di->abuffer, DGAVECS );
-
- rassize = RASSIZE( (long) im->Width, (long) im->Height );
- if ( tmpraster = (UBYTE *) AllocMem( rassize, MEMF_CHIP ) )
- {
- InitTmpRas( &di->tmpras, tmpraster, rassize );
- }
- else /* abort */
- {
- D( printf("CDG: couldn't get tmpraster size: %d\n", rassize ));
- FreeGadgets( g );
- g = NULL;
- }
- }
-
- return ( g );
- }
-
- DeleteDialGadget( g )
- struct Gadget *g;
- {
- struct TmpRas *tmpras = &DI( g )->tmpras;
-
- /* free off tmp raster */
- FreeMem( tmpras->RasPtr, tmpras->Size );
-
- /* delete gadget, special info, ... */
- g->NextGadget = NULL;
- FreeGadgets( g );
- }
-
- /* returns TRUE if normalized coord values have changed */
- SetDialCoords( g, x, y )
- struct Gadget *g;
- {
- WORD oldx, oldy;
- /* struct DialInfo *di = DI( g ); */
-
- if ( !( x || y ) )
- {
- return ( SetDialCoords( g, 0, 1 ) );
- }
-
- GetDialCoords( g, &oldx, &oldy );
-
- DI(g)->coordX = x;
- DI(g)->coordY = y;
- normalizeDialCoords( g );
-
- /* check for changes */
- GetDialCoords( g, &x, &y );
-
- return ( x != oldx || y != oldy );
- }
-
- GetDialCoords( g, xp, yp )
- struct Gadget *g;
- WORD *xp;
- WORD *yp;
- {
- *xp = DI(g)->coordX;
- *yp = DI(g)->coordY;
- }
-
- static
- drawNeedle( rp, g, left, top )
- struct RastPort *rp;
- struct Gadget *g;
- {
- struct DialInfo *di = DI( g );
- long centerX;
- long centerY;
- struct TmpRas *savetr;
- struct AreaInfo *saveai;
-
- /**** set up my tmpras/ainfo in Intuition's rastport ****/
- savetr = rp->TmpRas;
- saveai = rp->AreaInfo;
-
- rp->TmpRas = &di->tmpras;
- rp->AreaInfo = &di->ainfo;
-
- centerX = CENTER( g->Width );
- centerY = CENTER( g->Height );
-
- SetAPen( rp, NEEDLEPEN );
-
- AreaMove( rp, left + centerX + di->baseX,
- top + centerY + di->baseY );
-
- AreaDraw( rp, left + centerX - di->baseX,
- top + centerY - di->baseY );
-
- AreaDraw( rp, left + centerX + di->coordX,
- top + centerY + di->coordY );
-
- AreaEnd( rp );
-
- /*** restore Intuition's tmpras and ainfo ***/
- rp->TmpRas = savetr;
- rp->AreaInfo = saveai;
- }
-
- /*** internal number crunching ***/
-
- struct FPoint {
- float fX;
- float fY;
- };
-
- /*
- * converts values of coordX coordY to ray equivalent
- * coordinates on ellipse boundary of dial.
- * Never call this if the coords are both zero.
- */
- static
- normalizeDialCoords( g )
- struct Gadget *g;
- {
- struct DialInfo *di = DI( g );
- struct FPoint edge;
- struct FPoint base;
- WORD halfx = CENTER( g->Width );
- WORD halfy = CENTER( g->Height );
- float norm;
- Point ray;
-
- ray.x = di->coordX;
- ray.y = di->coordY;
-
- norm = (float) halfy * halfy * ray.x * (float) ray.x +
- (float) halfx * halfx * ray.y * (float) ray.y;
-
- norm = sqrt( (double) norm );
-
- /* I forgot what clever math leads to this */
- edge.fX = (float) halfy * ray.x / norm;
- edge.fY = (float) halfx * ray.y / norm;
-
- base.fX = edge.fY / BASEFACTOR;
- base.fY = - edge.fX / BASEFACTOR;
-
- di->coordX = halfx * edge.fX;
- di->coordY = halfy * edge.fY;
-
- di->baseX = halfx * base.fX;
- di->baseY = halfy * base.fY;
- }
-
- /**** the hook functions ****/
- /* Note: these functions run as the input.device task.
- * This means, among other things, that you can't do printf's
- * to your own process's output window.
- *
- * Also, it is not safe to call Intuition or Graphics, except as
- * documented for Intuition hook functions.
- */
-
- ULONG
- dial_Dispatch( hook, g, msg )
- struct Hook *hook; /* I don't have any use for this */
- struct Gadget *g;
- ULONG *msg; /* only interested in HookID */
- {
- ULONG retval = 0;
-
- D( kprintf("\ndial_Dispatch. hook %lx, g %lx, msg: %lx id %ld\n",
- hook, g, msg, *msg ) );
-
- switch ( (WORD) *msg )
- {
- case GM_HITTEST:
- /*
- * for now, if it's in the select box, we'll call it
- * a hit. (Might mask test or restrict to ellipse later.)
- * Note that this function is only called if select box
- * test has passed in Intuition.
- */
- retval = GMR_GADGETHIT;
- break;
-
- case GM_RENDER:
- retval = dial_render( g, msg );
- break;
-
- case GM_GOINACTIVE:
- /*
- * since this gadget doesn't have any special allocations
- * or processing when it is made active, this function
- * is a no-op
- */
- retval = 0;
- break;
-
- case GM_GOACTIVE: /* first input event */
- case GM_HANDLEINPUT: /* subsequent input events */
- retval = dial_handleinput( g, msg );
- break;
- }
- return ( retval );
- }
-
- /*
- * this implementation has no highlighting visuals.
- * so, if redraw is 0, I don't draw at all.
- * Note that I use this function to update the visuals
- * in dial_handleinput, in which case a NULL hook is passed.
- * This would change if you wanted some more subtle incremental
- * changing while the mouse was moved.
- */
- static ULONG
- dial_render( g, msg )
- struct Gadget *g;
- struct gpRender *msg;
- {
- ULONG dial_realrender();
-
- return( dial_realrender( g, msg->gpr_GInfo,
- msg->gpr_RPort, msg->gpr_Redraw ) );
- }
-
- static ULONG
- dial_realrender( g, gi, rp, redraw )
- struct Gadget *g;
- struct GadgetInfo *gi;
- struct RastPort *rp;
- LONG redraw;
- {
- /* this code uses the gadget select box as is, therefore,
- * this gadget doesn't support relative positioning or dimensions
- */
-
- if ( redraw )
- {
- DrawImage( rp, g->GadgetRender, g->LeftEdge, g->TopEdge );
- drawNeedle( rp, g, g->LeftEdge, g->TopEdge );
- }
-
- return ( 0 );
- }
-
-
- static ULONG
- dial_handleinput( g, msg )
- struct Gadget *g;
- struct gpInput *msg;
- {
- struct GadgetInfo *gi = msg->gpi_GInfo;
- struct RastPort *ObtainGIRPort();
- struct RastPort *rp;
- Point mouse;
- ULONG retval = 0;
- struct InputEvent *ie = msg->gpi_IEvent;
-
- if ( ie->ie_Class == IECLASS_RAWMOUSE )
- {
- mouse.x = msg->gpi_Mouse.X;
- mouse.y = msg->gpi_Mouse.Y;
-
- /* only redraw if it has moved */
- if ( SetDialCoords( g,
- mouse.x - CENTER( g->Width ), mouse.y - CENTER( g->Height ) ) )
- {
- /* you have to ask permission to use the right rastport
- * if it isn't provided in the message packet (gpRender
- * is the only case of that).
- */
- rp = ObtainGIRPort( gi );
-
- /* render it with new coord values */
- dial_realrender( g, gi, rp, 1L );
-
- ReleaseGIRPort( rp );
- }
-
- /* determine if we are done */
-
- /* menu button: abort, input reused */
- if ( ie->ie_Code == IECODE_RBUTTON )
- {
- *msg->gpi_Termination = 1; /* aborted by menu button */
- retval = GMR_REUSE | GMR_VERIFY;
- }
- /* select up: user is done, don't reuse input event */
- else if ( ie->ie_Code == (IECODE_LBUTTON | IECODE_UP_PREFIX ) )
- {
- *msg->gpi_Termination = 0; /* normal termination */
- retval = GMR_NOREUSE | GMR_VERIFY;
- }
- }
-
- D( kprintf( "d_hi returning: %lx\n", retval ) );
- return ( retval );
- }
-